import {
  Delete,
  ExecutionContext,
  HttpException,
  HttpStatus,
  Injectable,
} from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";
import { Reflector } from "@nestjs/core";
import { AuthService } from "@/modules/auth/auth.service";
import { Enabled } from "@/common/enums/enabled.enum";
import { Deleted } from "@/common/enums/deleted.enum";

@Injectable()
export class JwtAuthGuard extends AuthGuard("jwt") {
  constructor(
    private reflector: Reflector,
    private readonly authService: AuthService
  ) {
    super();
  }
  async canActivate(context: ExecutionContext) {
    const isPublic = this.reflector.getAllAndOverride("isPublic", [
      context.getHandler(),
      context.getClass(),
    ]);
    if (isPublic) return true;
    try {
      //校验tenantId是否有效
      await this.checkTenantId(context);
      //校验token是否过期
      await this.checkToken(context);
      return this.activate(context);
    } catch (error) {
      throw error;
    }
  }
  async activate(context: ExecutionContext): Promise<boolean> {
    return super.canActivate(context) as Promise<boolean>;
  }

  async checkTenantId(context: ExecutionContext) {
    const req = context.switchToHttp().getRequest();
    const tenantId = req.get("tenant-id");
    console.log("checkTenantId", tenantId);
    if (!tenantId) {
      throw new HttpException(
        "quick-tenant-id is null",
        HttpStatus.UNAUTHORIZED
      );
    }
    try {
      const payload = await this.authService.verifyTenantId(tenantId);
      const { id, deleted, enabled, balance } = payload;
      if (!id) {
        throw new HttpException(
          "租户编号无效,请重新输入，多次输入仍无效请联系管理员.",
          HttpStatus.UNAUTHORIZED
        );
      } else if (enabled === Enabled.Disable) {
        throw new HttpException(
          "租户已禁用,请联系管理员开启.",
          HttpStatus.UNAUTHORIZED
        );
      } else if (deleted === Deleted.Deleted) {
        throw new HttpException(
          "租户已删除,请联系管理员开启.",
          HttpStatus.UNAUTHORIZED
        );
      } else if (balance <= 0) {
        throw new HttpException(
          "租户余额不足,请联系管理员充值.",
          HttpStatus.UNAUTHORIZED
        );
      }
    } catch (error) {
      throw new HttpException(
        "租户编号无效,请重新输入.",
        HttpStatus.UNAUTHORIZED
      );
    }
  }

  async checkToken(context: ExecutionContext) {
    const req = context.switchToHttp().getRequest();
    const accessToken = req.get("Authorization");
    if (!accessToken) {
      throw new HttpException("请先登录", HttpStatus.UNAUTHORIZED);
    }
    if (accessToken.indexOf("Bearer") === -1) {
      throw new HttpException("token未包含Bearer头", HttpStatus.UNAUTHORIZED);
    }
    try {
      const tokenStr = accessToken.replace("Bearer ", "");
      const payload = await this.authService.verifyToken(tokenStr);
      const { userName } = payload;
      if (!userName) {
        throw new HttpException(
          "当前登录已过期,请重新登录.",
          HttpStatus.UNAUTHORIZED
        );
      }
    } catch (error) {
      throw new HttpException(
        "当前登录已过期,请重新登录.",
        HttpStatus.UNAUTHORIZED
      );
    }
  }
}
